package com.roger.redis;

import java.util.List;
import java.util.Map;
import java.util.Set;

import redis.clients.jedis.BinaryClient.LIST_POSITION;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.SortingParams;

public class RedisUtil {
	
	private Jedis jedis;
	
	private static class JedPool{
		
		private static int PORT = 6379;
		
		private static JedisPool pool;
		
		/**
	     * 构建redis连接池
	     * 
	     * @param ip
	     * @param port
	     * @return JedisPool
	     */
	    public synchronized static JedisPool getPool() {
	    	
	        if (pool == null) {
	            JedisPoolConfig config = new JedisPoolConfig();
	            //控制一个pool可分配多少个jedis实例，通过pool.getResource()来获取；
	            //如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
	            config.setMaxActive(500);
	            //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
	            config.setMaxIdle(5);
	            //表示当borrow(引入)一个jedis实例时，最大的等待时间，如果超过等待时间，则直接抛出JedisConnectionException；
	            config.setMaxWait(1000 * 100L);
	            //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
	            config.setTestOnBorrow(true);
	            
	            pool = new JedisPool(config, "127.0.0.1", PORT);
	        }
	        return pool;
	    }
	}
	
	
	private static Jedis getJedis(){
		return JedPool.getPool().getResource();
	}
	
	public RedisUtil(){
		jedis = RedisUtil.getJedis();
	}
	
	public RedisUtil(String host,int port){
		JedPool.PORT = port;
		jedis = RedisUtil.getJedis();
	}
	
	public void selectDB(int db){
		jedis.select(db);
	}
	
	public String set(byte[] key,byte[] value){
		return jedis.set(key, value);
	}
	
	/**
	 * SETNX works exactly like SET with the only difference that 
	 * if the key already exists no operation is performed.
	 * @param key
	 * @param value
	 * @return
	 */
	public Long setNotExist(String key,String value){
		return jedis.setnx(key,value);
	}
	
	/**
	 * return a random value
	 * @return
	 */
	public String randomGet(){
		String key = jedis.randomKey();
		return jedis.get(key);
	}
	
	/**
	 * Get the value of the specified key.
	 * @param key
	 * @return
	 */
	public String get(String key){
		return jedis.get(key);
	}
	
	public byte[] get(byte[] key){
		return jedis.get(key);
	}
	
	/**
	 * If the key already exists and is a string, 
	 * this command appends the provided value at the end of the string.
	 * @param key
	 * @param value
	 */
	public void append(String key,String value){
		jedis.append(key,value);
	}
	
	/**
	 * Decrement the number stored at key by one.
	 * @param key
	 * @return
	 */
	public Long decr(String key){
		return jedis.decr(key);
	}
	
	/**
	 * IDECRBY work just like INCR but instead to decrement by 1 the decrement is integer.
	 * @param key
	 * @param integer
	 * @return
	 */
	public Long decrBy(String key, long integer){
		return jedis.decrBy(key,integer);
	}
	
	/**
	 * Increment the number stored at key by one.
	 * @param key
	 * @return
	 */
	public Long incr(String key){
		return jedis.incr(key);
	}
	
	/**
	 * INCRBY work just like INCR but instead to increment by 1 the increment is integer
	 * @param key
	 * @param integer
	 * @return
	 */
	public Long incrBy(String key, long integer){
		return jedis.incrBy(key, integer);
	}
	
	public String set(String key,String value){
		return jedis.set(key, value);
	}
	
	//end String
	
	//start list
	/**
	 * Add the string value to the head (LPUSH) of the list stored at key.
	 * @param key
	 * @param value
	 */
	public Long listLeftPush(String key,String value){
		return jedis.lpush(key, value);
	}
	
	/**
	 * Add the string value to the tail (RPUSH) of the list stored at key.
	 * @param key
	 * @param value
	 * @return
	 */
	public Long listRightPush(String key,String value){
		return jedis.rpush(key, value);
	}
	
	/**
	 * Atomically return and remove the first (LPOP) element of the list.
	 * @param key
	 * @return
	 */
	public String listLeftPop(String key){
		return jedis.lpop(key);
	}
	
	/**
	 * Atomically return and remove the last (RPOP) element of the list.
	 * @param key
	 * @return
	 */
	public String listRightPop(String key){
		return jedis.rpop(key);
	}
	
	/**
	 * @param timeout
	 * @param keys
	 * @return List
	 */
	public List<String> listBlockLeftPop(int timeout,String...keys){
		return jedis.blpop(timeout, keys);
	}
	
	/**
	 * @param timeout
	 * @param keys
	 * @return List
	 */
	public List<String> listBlockRightPop(int timeout,String...keys){
		return jedis.brpop(timeout, keys);
	}
	
	/**
	 * Return the length of the list stored at the specified key.
	 * @param key
	 * @return
	 */
	public Long listLen(String key){
		return jedis.llen(key);
	}
	
	/**
	 * Return the specified element of the list stored at the specified key.
	 * @param key
	 * @param index
	 * @return
	 */
	public String listGetIndex(String key,long index){
		return jedis.lindex(key, index);
	}
	
	/**
	 * Set a new value as the element at index position of the List at key.
	 * @param key
	 * @param index
	 * @param value
	 */
	public void listUpdate(String key,long index,String value){
		jedis.lset(key, index, value);
	}
	
	/**
	 * @param key
	 * @param where
	 * @param pivot
	 * @param value
	 */
	public void listInsert(String key,LIST_POSITION where,String pivot,String value){
		jedis.linsert(key, where, pivot, value);
	}
	
	/**
	 * Return the specified elements of the list stored at the specified key.
	 * @param key
	 * @param start
	 * @param end
	 */
	public List<String> listRange(String key, long start, long end){
		return jedis.lrange(key, start, end);
	}
	
	/**
	 * Remove the first count occurrences of the value element from the list.
	 * @param key
	 * @param count
	 * @param value
	 * @return
	 */
	public Long listRemove(String key, long count, String value){
		return jedis.lrem(key, count, value);
	}
	
	//end list
	
	//start hash
	/**
	 * Set the specified hash field to the specified value.
	 * @param key
	 * @param field
	 * @param value
	 */
	public Long hashSet(String key,String field,String value){
		return jedis.hset(key, field, value);
	}
	
	/**
	 * Set the specified hash field to the specified value if the field not exists.
	 * @param key
	 * @param field
	 * @param value
	 * @return
	 */
	public Long hashSetNotExist(String key, String field, String value){
		return jedis.hsetnx(key,field,value);
	}
	
	/**
	 * If key holds a hash, retrieve the value associated to the specified field.
	 * @param key
	 * @param field
	 * @return
	 */
	public String hashGet(String key,String field){
		return jedis.hget(key, field);
	}
	
	/**
	 * Return all the fields and associated values in a hash.
	 * @param key
	 * @return
	 */
	public Map<String,String> hashGetAll(String key){
		return jedis.hgetAll(key);
	}
	
	/**
	 * Remove the specified field from an hash stored at key.
	 * @param key
	 * @param field
	 */
	public void hashDel(String key,String field){
		jedis.hdel(key, field);
	}
	
	/**
	 * Test for existence of a specified field in a hash.
	 * @param key
	 * @param field
	 * @return
	 */
	public boolean hashExist(String key,String field){
		return jedis.hexists(key, field);
	}
	
	/**
	 * Return the number of items in a hash.
	 * @param key
	 * @return
	 */
	public Long hashLen(String key){
		return jedis.hlen(key);
	}
	
	/**
	 * Return all the fields in a hash.
	 * @param key
	 * @return
	 */
	public Set<String> hashFields(String key){
		return jedis.hkeys(key);
	}
	
	/**
	 * Return all the values in a hash.
	 * @param key
	 * @return
	 */
	public List<String> hashValues(String key){
		return jedis.hvals(key);
	}
	
	/**
	 * Increment the number stored at field in the hash at key by value.
	 * @param key
	 * @param field
	 * @param value
	 * @return
	 */
	public Long hashIncrBy(String key, String field, long value){
		return jedis.hincrBy(key, field, value);
	}

	//end hash
	
	//start set
	/**
	 * Add the specified member to the set value stored at key.
	 * @param key
	 * @param member
	 */
	public void setAdd(String key,String member){
		jedis.sadd(key, member);
	}
	
	/**
	 * @param key
	 * @return
	 */
	public String setGetRandMember(String key){
		return jedis.srandmember(key);
	}
	
	/**
	 * Return all the members (elements) of the set value stored at key.
	 * @param key
	 * @return
	 */
	public Set<String> setGetMembers(String key){
		return jedis.smembers(key);
	}
	
	/**
	 * Return 1 if member is a member of the set stored at key, otherwise 0 is returned.
	 * @param key
	 * @param member
	 * @param db
	 * @return
	 */
	public boolean setIsMember(String key,String member){
		return jedis.sismember(key, member);
	}
	
	/**
	 * Return the set cardinality (number of elements).
	 * @param key
	 * @return
	 */
	public Long setLen(String key){
		return jedis.scard(key);
	}
	
	/**
	 * Move the specifided member from the set at srckey to the set at dstkey.
	 * @param srckey
	 * @param dstkey
	 * @param member
	 * @return
	 */
	public Long setMove(String srckey,String dstkey,String member){
		return jedis.smove(srckey, dstkey, member);
	}
	
	/**
	 * Return the difference between the Set stored at key1 and all the Sets key2, ..., keyN
	 * @param keys
	 * @return
	 */
	public Set<String> setDiff(String...keys){
		return jedis.sdiff(keys);
	}
	
	/**
	 * Return the members of a set resulting from the intersection of 
	 * all the sets hold at the specified keys.
	 * @param keys
	 * @return
	 */
	public Set<String> setIntersection(String... keys){
		return jedis.sinter(keys);
	}
	
	/**
	 * Return the members of a set resulting from the union of all the sets hold at the specified keys.
	 * @param keys
	 * @return
	 */
	public Set<String> setUnion(String...keys){
		return jedis.sunion(keys);
	}
	
	/**
	 * Remove the specified member from the set value stored at key.
	 * @param key
	 * @param member
	 * @return
	 */
	public Long setRemove(String key,String member){
		return jedis.srem(key, member);
	}
	
	//end Set
	
	//start sort
	/**
	 * Sort a Set or a List.
	 * @param key
	 * @return
	 */
	public List<String> sort(String key){
		return jedis.sort(key);
	}
	
	/**
	 * Sort a Set or a List accordingly to the specified parameters.
	 * @param key
	 * @param sortingParameters
	 * @return
	 */
	public List<String> sort(String key,SortingParams sortingParameters){
		return jedis.sort(key,sortingParameters);
	}
	//end sort
	
	
	/**
	 * Remove the specified keys.
	 * @param key
	 */
	public void remove(String...keys){
		jedis.del(keys);
	}
	
	/**
	 * Test if the specified key exists.
	 * @param key
	 * @return
	 */
	public boolean exist(String key){
		return jedis.exists(key);
	}
	
	/**
	 * Set a timeout on the specified key.
	 * @param key
	 * @param seconds
	 * @return
	 */
	public Long expire(String key, int seconds){
		return jedis.expire(key, seconds);
	}
	
	/**
	 * Returns all the keys matching the glob-style pattern as space separated strings.
	 * @param pattern
	 * @return
	 */
	public Set<String> keys(String pattern){
		return jedis.keys(pattern);
	}
	
	/**
	 * Move the specified key from the currently selected DB to the specified destination DB.
	 * @param db
	 * @param key
	 * @return
	 */
	public Long move(int db,String key){
		return jedis.move(key, db);
	}
	
	/**
	 * Undo a expire at turning the expire key into a normal key.
	 * @param key
	 * @return
	 */
	public Long persist(String key){
		return jedis.persist(key);
	}
	
	/**
	 * Return a randomly selected key from the currently selected DB.
	 * @return
	 */
	public String randomKey(){
		return jedis.randomKey();
	}
	
	/**
	 *  Atomically renames the key oldkey to newkey.
	 * @param oldkey
	 * @param newkey
	 * @return
	 */
	public String rename(String oldkey, String newkey){
		return jedis.rename(oldkey, newkey);
	}
	
	/**
	 * Rename oldkey into newkey but fails if the destination key newkey already exists.
	 * @param oldkey
	 * @param newkey
	 * @return
	 */
	public Long renamenx(String oldkey, String newkey){
		return jedis.renamenx(oldkey, newkey);
	}
	
	/**
	 * Return the type of the value stored at key in form of a string.
	 * @param key
	 * @return
	 */
	public String type(String key){
		return jedis.type(key);
	}

	/**
	 * Return the number of keys in the currently selected database
	 * @return
	 */
	public Long getDBSize(){
		return jedis.dbSize();
	}
	
	/**
	 * dull with save RDB
	 */
	public void saveRDB(){
		jedis.save();
	}
	
	/**
	 * dull with back-ground WriteAOF
	 */
	public void bgReWriteAOF(){
		jedis.bgrewriteaof();
	}
	
	/**
	 * get db index
	 * @return
	 */
	public Long getDB(){
		return jedis.getDB();
	}
	
	/**
	 * Select the DB with having the specified zero-based numeric index.
	 * @param db
	 */
	public void select(int db){
		jedis.select(db);
	}
	
	/**
	 * Delete all the keys of all the existing databases, 
	 * not just the currently selected one.
	 */
	public void flushAll(){
		jedis.flushAll();
	}
	
	/**
	 * Delete all the keys of the selected DB.
	 * @param db
	 */
	public void flushDB(){
		jedis.flushDB();
	}
	
	/**
	 * delete all
	 */
	public void cleanAll(){
		jedis.flushAll();
	}
	
	/**
	 * delete all redis
	 */
	public void cleanDB(){
		jedis.flushDB();
	}
	
	/**
	 * Request for authentication in a password protected Redis server
	 * @param password
	 */
	public void auth(String password){
		jedis.auth(password);
	}
	
	/**
	 * @param jedisPubSub
	 * @param channels
	 */
	public void subscribe(JedisPubSub jedisPubSub,String...channels){
		jedis.subscribe(jedisPubSub, channels);
	}
	
	/**
	 * @param jedisPubSub
	 * @param patterns
	 */
	public void psubscribe(JedisPubSub jedisPubSub,String...patterns){
		jedis.psubscribe(jedisPubSub, patterns);
	}
	
	/**
	 * @param channel
	 * @param message
	 */
	public void publish(String channel,String message){
		jedis.publish(channel, message);
	}
	
	/**
	 * @param host
	 * @param port
	 */
	public void salveOfServer(String host,int port){
		jedis.slaveof(host, port);
	}
}
